package com.lagou.rpc.consumer.proxy;

import com.alibaba.fastjson.JSON;
import com.lagou.rpc.common.RpcRequest;
import com.lagou.rpc.common.RpcResponse;
import com.lagou.rpc.consumer.client.RpcClient;
import com.lagou.rpc.consumer.config.Config;
import com.lagou.rpc.consumer.config.MyClientConfig;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;

/**
 * 客户端代理类-创建代理对象
 * 1.封装request请求对象
 * 2.创建RpcClient对象
 * 3.发送消息
 * 4.返回结果
 */
@Component
public class RpcClientProxy {


    private static MyClientConfig myClientConfig;
    static {
        myClientConfig = new MyClientConfig();
        myClientConfig.setConfigs(new ArrayList<>());
//        myClientConfig.setConfigs(Arrays.asList(new Config("127.0.0.1",9991),new Config("127.0.0.1",9992),new Config("127.0.0.1",9993)));

    }

    private static ZkClient zkClient;

    private static final String PATH = "/my_server";

    @PostConstruct
    public void queryServer(){
        zkClient = new ZkClient("192.168.172.130:2181");
        System.out.println("查找可用服务。。。");
        List<String> serverList = zkClient.subscribeChildChanges(PATH, new IZkChildListener() {

            @Override
            public void handleChildChange(String parentPath, List<String> list) throws Exception {
                System.out.println(parentPath + "的子节点列表发生了变化,变化后的子节点列表为" + list);
                myClientConfig.setConfigs(new ArrayList<>());
                for (String s : list) {
                    String[] split = s.split(":");
                    myClientConfig.getConfigs().add(new Config(split[0],Integer.parseInt(split[1])));
                }

            }
        });

        System.out.println(serverList);
        if (!CollectionUtils.isEmpty(serverList)){
            myClientConfig.setConfigs(new ArrayList<>());
            for (String s : serverList) {
                String[] split = s.split(":");
                myClientConfig.getConfigs().add(new Config(split[0],Integer.parseInt(split[1])));
            }
        }
    }


    public static Object createProxy(Class serviceClass) {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[]{serviceClass}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //1.封装request请求对象
                        RpcRequest rpcRequest = new RpcRequest();
                        rpcRequest.setRequestId(UUID.randomUUID().toString());
                        rpcRequest.setClassName(method.getDeclaringClass().getName());
                        rpcRequest.setMethodName(method.getName());
                        rpcRequest.setParameterTypes(method.getParameterTypes());
                        rpcRequest.setParameters(args);
                        //2.创建RpcClient对象
//                        RpcClient rpcClient = new RpcClient("127.0.0.1", 9991);
                        ZkClient zkClient1 = new ZkClient("192.168.172.130:2181");
                        List<String> children =zkClient1.getChildren(PATH);
                        if (CollectionUtils.isEmpty(children)){
                            throw new RuntimeException("没有可用服务");
                        }
                        int port = -1;
                        String ip = "";
                        Long temp =Long.MAX_VALUE;
                        Long temp2 = -1L;
                        for (String child : children) {
                            Map<String,Object> o = RpcClientProxy.zkClient.readData(PATH+"/"+child);
                            if (o==null){
                                String[] split = child.split(":");
                                ip = split[0];
                                port = Integer.parseInt(split[1]);
                                break;
                            }
                            Object reqTimeObj = o.get("reqTime");

                            if (reqTimeObj == null){
                                String[] split = child.split(":");
                                ip = split[0];
                                port = Integer.parseInt(split[1]);
                                break;
                            }
                            Long reqTime = (Long) reqTimeObj;
                            if (reqTime<=temp) {
                                String[] split = child.split(":");
                                ip = split[0];
                                port = Integer.parseInt(split[1]);
                                temp = reqTime;
                                temp2 = reqTime;
                            }
                        }
                        System.out.println("选择了："+ip+":"+port+"  上次请求耗时："+temp2);
                        RpcClient rpcClient = new RpcClient(ip,port);
                        try {
                            long startTime = System.currentTimeMillis();
                            //3.发送消息
                            Object responseMsg = rpcClient.send(JSON.toJSONString(rpcRequest));
                            RpcResponse rpcResponse = JSON.parseObject(responseMsg.toString(), RpcResponse.class);
                            if (rpcResponse.getError() != null) {
                                throw new RuntimeException(rpcResponse.getError());
                            }
                            //4.返回结果
                            Object result = rpcResponse.getResult();
                            long endTime = System.currentTimeMillis();
                            String serverPath = PATH+"/"+ip+":"+port;
                            Map map = new HashMap();
                            map.put("sysTime",endTime);
                            map.put("reqTime",endTime-startTime);
                            RpcClientProxy.zkClient.writeData(serverPath, map);
                            return JSON.parseObject(result.toString(), method.getReturnType());
                        } catch (Exception e) {
                            throw e;
                        } finally {
                            rpcClient.close();
                        }

                    }
                });
    }
}
